/**
 *
 */
package anyware.common.restlet;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.activation.FileTypeMap;
import javax.activation.MimetypesFileTypeMap;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.restlet.Filter;
import org.restlet.data.MediaType;
import org.restlet.data.Preference;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Restlet Filter to tunnel type according to Restlet request. Tunnelling goes
 * on two steps:
 * <ol>
 * <li>First will check whether request URL has file extension, eg.
 * {@code http://example.com/resource.json}, if so, will use
 * {@link FileTypeMap} to get its mime name and then create an instance of
 * {@link MediaType} using that mime name.</li>
 * <li>Then if no extension is specified, will try to get the content type from http
 * header {@code Accept-Type}. If multiple content type are specified, the one
 * with largest quality value will be used. </ii>
 * </ol>
 * 
 * @author keke<keke@codehaus.org>
 * @revision $Revision: 132 $
 * @version 0.0.2
 * @see FileTypeMap
 * @see MimetypesFileTypeMap - for how to define your own mime.types file.
 */
public class TypeTunnelFilter extends Filter {
    private static final Logger LOG  = LoggerFactory
                                             .getLogger(TypeTunnelFilter.class);

    public static final String  TYPE = TypeTunnelFilter.class.getName()
                                             + ".TYPE";

    /*
     * (non-Javadoc)
     * 
     * @see org.restlet.Filter#afterHandle(org.restlet.data.Request,
     *      org.restlet.data.Response)
     */
    @Override
    protected int beforeHandle(final Request request, final Response response) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("Before handling : {}", request.getResourceRef());
        }
        String ext = FilenameUtils.getExtension(request.getResourceRef()
                .toString());
        MediaType mediaType = null;
        if (StringUtils.isEmpty(ext)) {
            // will try to check accept-type
            // At current moment, simple get the one with biggest quality value.
            List<Preference<MediaType>> preferredTypes = request
                    .getClientInfo().getAcceptedMediaTypes();
            Preference<MediaType> preferred = Collections.max(preferredTypes,
                    new Comparator<Preference<MediaType>>() {
                        public int compare(Preference<MediaType> o1,
                                Preference<MediaType> o2) {
                            float q1 = o1.getQuality();
                            float q2 = o2.getQuality();
                            return q1 == q2 ? 0 : q1 > q2 ? 1 : -1;
                        }
                    });
            if (preferred != null) {
                mediaType = preferred.getMetadata();
            }
        } else {
            mediaType = MediaType.valueOf(FileTypeMap.getDefaultFileTypeMap()
                    .getContentType("File." + ext));
        }
        request.getAttributes().put(TYPE, mediaType);
        // always continue.
        return Filter.CONTINUE;
    }
}
